﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace undeadtank
{
    class Camera
    {
        public Viewport viewport;
        Matrix view;
        Matrix proj;
        Matrix world;

        // Set the avatar position and rotation variables.
        Vector3 avatarPosition;
        Vector3 avatarHeadOffset;
        float avatarYaw;

        // Set the direction the camera points without rotation.
        Vector3 cameraReference;
        Vector3 thirdPersonReference;
        Vector3 mapReference;

        // Set field of view of the camera in radians (pi/4 is 45 degrees).
        static float viewAngle;

        // Set distance from the camera of the near and far clipping planes.
        //static float nearClip;
        static float nearClip;
        static float farClip;

        // Set the camera state, avatar's center, first-person, third-person.
        public int cameraState;
        bool cameraStateKeyDown;

        // Set rates in world units per 1/60th second (the default fixed-step interval).
        float rotationSpeed;
        float forwardSpeed;

        public Camera(Viewport vp)
        {
            // Set the avatar position and rotation variables.
            avatarPosition = new Vector3(0, 0, 3);
            avatarHeadOffset = new Vector3(0, 1.99f, -0.15f);
            avatarYaw = 0.0f;

            // Set the direction the camera points without rotation.
            cameraReference = new Vector3(0, 0, 3);
            thirdPersonReference = new Vector3(0, 50, -50);
            mapReference = new Vector3(0, 50, -1);

            // Set field of view of the camera in radians (pi/4 is 45 degrees).
            viewAngle = MathHelper.PiOver4;

            // Set distance from the camera of the near and far clipping planes.
            nearClip = 0.1f;
            farClip = 500.0f;

            // Set rates in world units per 1/60th second (the default fixed-step interval).
            rotationSpeed = 1f / 60f;
            forwardSpeed = 50f / 60f;

            this.viewport = vp;

            float aspectRatio = (float)this.viewport.Width / (float)this.viewport.Height;

            proj = Matrix.CreatePerspectiveFieldOfView(
                viewAngle,
                aspectRatio,
                nearClip,
                farClip);
        }

        public Matrix getWorld()
        {
            return this.world;
        }

        public Matrix getView()
        {
            return this.view;
        }

        public Matrix getProj()
        {
            return this.proj;
        }

        public Vector3 getAvatarPosition()
        {
            return this.avatarPosition;
        }

        public void setCameraState(int state)
        {
            this.cameraState = state;
        }

        public void Draw()
        {
            switch (this.cameraState)
            {
                default:
                case 0:
                    UpdateCameraThirdPerson();
                    break;
                case 1:
                    UpdateCameraFirstPerson();
                    break;
                case 2:
                    UpdateCameraMap();
                    break;
            }
            world = Matrix.CreateRotationY(avatarYaw) * Matrix.CreateTranslation(avatarPosition);
        }

        public void Update(KeyboardState teclado)
        {
            this.GetCurrentCamera(teclado);
            this.UpdateAvatarPosition(teclado);
        }


        // Update the position and direction of the avatar.
        void UpdateAvatarPosition(KeyboardState teclado)
        {
            KeyboardState keyboardState = teclado;
            GamePadState currentState = GamePad.GetState(PlayerIndex.One);

            if (keyboardState.IsKeyDown(Keys.Left) ||
                (currentState.DPad.Left == ButtonState.Pressed))
            {
                // Rotate left.
                avatarYaw += rotationSpeed;
            }
            if (keyboardState.IsKeyDown(Keys.Right) ||
                (currentState.DPad.Right == ButtonState.Pressed))
            {
                // Rotate right.
                avatarYaw -= rotationSpeed;
            }
            if (keyboardState.IsKeyDown(Keys.Up) || (currentState.DPad.Up == ButtonState.Pressed))
            {
                Matrix forwardMovement = Matrix.CreateRotationY(avatarYaw);
                Vector3 v = new Vector3(0, 0, forwardSpeed);
                v = Vector3.Transform(v, forwardMovement);
                avatarPosition.Z += v.Z;
                avatarPosition.X += v.X;
            }
            if (keyboardState.IsKeyDown(Keys.Down) || (currentState.DPad.Down == ButtonState.Pressed))
            {
                Matrix forwardMovement = Matrix.CreateRotationY(avatarYaw);
                Vector3 v = new Vector3(0, 0, -forwardSpeed);
                v = Vector3.Transform(v, forwardMovement);
                avatarPosition.Z += v.Z;
                avatarPosition.X += v.X;
            }
        }

        void GetCurrentCamera(KeyboardState teclado)
        {
            KeyboardState keyboardState = teclado;
            GamePadState currentState = GamePad.GetState(PlayerIndex.One);

            // Toggle the state of the camera.
            /*if (keyboardState.IsKeyDown(Keys.Tab) ||
                (currentState.Buttons.LeftShoulder == ButtonState.Pressed))
            {
                cameraStateKeyDown = true;
            }
            else if (cameraStateKeyDown == true)
            {
                cameraStateKeyDown = false;
                cameraState += 1;
                cameraState %= 2;
            }*/
        }

        void UpdateCameraFirstPerson()
        {
            Matrix rotationMatrix = Matrix.CreateRotationY(avatarYaw);

            // Calculate the camera's current position.
            Vector3 cameraPosition = avatarPosition;

            // Create a vector pointing the direction the camera is facing.
            Vector3 transformedReference = Vector3.Transform(cameraReference, rotationMatrix);

            // Calculate the position the camera is looking at.
            Vector3 cameraLookat = cameraPosition + transformedReference;

            // Set up the view matrix and projection matrix.
            view = Matrix.CreateLookAt(cameraPosition, cameraLookat, new Vector3(0.0f, 1.0f, 0.0f));
        }

        void UpdateCameraThirdPerson()
        {
            Matrix rotationMatrix = Matrix.CreateRotationY(avatarYaw);

            // Transform the head offset so the camera is positioned properly relative to the avatar.
            Vector3 headOffset = Vector3.Transform(avatarHeadOffset, rotationMatrix);

            // Calculate the camera's current position.
            Vector3 cameraPosition = avatarPosition + headOffset;

            // Create a vector pointing the direction the camera is facing.
            Vector3 transformedReference = Vector3.Transform(cameraReference, rotationMatrix);

            // Calculate the position the camera is looking at.
            Vector3 cameraLookat = transformedReference + cameraPosition;

            // Set up the view matrix and projection matrix.

            view = Matrix.CreateLookAt(cameraPosition, cameraLookat, new Vector3(0.0f, 1.0f, 0.0f));

        }

        void UpdateCameraMap()
        {
            Matrix rotationMatrix = Matrix.CreateRotationY(avatarYaw);

            // Create a vector pointing the direction the camera is facing.
            Vector3 transformedReference = Vector3.Transform(mapReference, rotationMatrix);

            // Calculate the position the camera is looking from.
            Vector3 cameraPosition = transformedReference + avatarPosition;

            // Set up the view matrix and projection matrix.
            view = Matrix.CreateLookAt(cameraPosition, avatarPosition, new Vector3(0.0f, 1.0f, 0.0f));
        }
    }
}